/*!
 *  Property.h
 *  IncrementalAlgorithmSerial
 *
 *  Created by Roman Kutlak on 29/03/2010.
 *  Copyright 2010 Roman Kutlak. All rights reserved.
 *
 */

#ifndef _PROPERTY_H_
#define _PROPERTY_H_

#include <string>
#include <iostream>
#include <algorithm>
#include <map>
#include <functional>

#include "Voc.h"
#include "Utilities.h"

namespace kutlak {
namespace roman {
namespace gre {
    
    
    
    //! \def DEFAULT_ATTRIBUTE
#define DEFAULT_ATTRIBUTE 0
    //! \def DEFAULT_VALUE
#define DEFAULT_VALUE 0
    
    //! Property serves as an encapsulation of Property for gre algorithms.
    /*! 
     * The class has an attribute and value pair along with a flag for negation 
     * and inverse of the attribute. The negation allows for meaning such as 
     * colour not black etc. and the inverse allows to change the meaning of having 
     * a particular property e.g. 'supervisedBy x' inverse would be 'x supervised.'
     * These two features are not used at the moment.
     */
    class Property 
    {
    public:
        
#pragma mark -
#pragma mark lifecycle
        //! Default constructor.
        /*! The default constructor takes two parameters - an attribute and a value.
         \param inAttribute is the string representing the attribute
         \param inValue is the string representing the value
         * Default values are used if needed.
         */
        explicit
        Property(const Vindex_t& inAttribute = DEFAULT_ATTRIBUTE,
                 const Vindex_t& inValue = DEFAULT_VALUE);
        
        explicit
        Property(const std::string& inAttribute,
                 const std::string& inValue = "");
        
        Property(const Vindex_t& inAttribute,
                 const std::string& inValue);
        
        Property(const Property& src);
        
        Property(Property&& src);
        
        Property& operator=(Property rhs) noexcept(true);
        
        friend void swap(Property& first, Property& second) noexcept(true);
        
        ~Property() noexcept(true);
        
#pragma mark -
#pragma mark operators
        
        //! The operator compares two properties.
        /*! The equality operator returns true if the two compared properties
         have the same attribute, value and flags.
         */
        bool operator==(const Property& rhs) const;
        bool operator!=(const Property& rhs) const;
        
        //! The comparison operators compare the properties lexically.
        /*! The property that has a lexically smaller attribute is smaller,
         if the attributes are identical, the property with lexically smaller
         value is smaller. e.g. property a b < b b and a d > a b.
         The operator can be used for map<Property>. 
         */
        bool operator<(const Property& rhs) const;
        //! The comparison operators compare the properties lexically.
        bool operator>(const Property& rhs) const;
        
#pragma mark -
#pragma mark I/O
        // Class is serialisable, it uses a custom format: 
        // <p> attr val neg inv </p>
        
        friend std::ostream& operator<<(std::ostream& os, const Property& obj);
        
        friend std::istream& operator>>(std::istream& is, Property& obj);
        
        void Serialise(std::ostream& os) const;
        
        void Deserialise(std::istream& is);
        
        // RDF representation; format: <attribute> <value>
        std::ostream& ToRdf(std::ostream& os) const;
        
        std::istream& FromRdf(std::istream& is);
        
        std::string ToRdf() const;
        
        // Format: Property attribute value
        std::string ToString() const;
        
#pragma mark -
#pragma mark accessors
        //! Returns a copy of the attribute.
        const Vindex_t& Attribute() const;
        std::string AttributeStr() const;
        
        //! Returns a copy of the value;
        const Vindex_t& Value() const;
        std::string ValueStr() const;
        
        //! Returns true if the property is negated.
        bool Negation() const;
        
        //! Returns true if the properti is an inverse
        bool Inverse() const;
        
        // setters
        void SetAttribute(const Vindex_t& att);
        void SetValue(const Vindex_t& val);
        
        void SetAttribute(const std::string& att);
        void SetValue(const std::string& val);
        
        void SetAttribute(std::string&& att);
        void SetValue(std::string&& val);
        
        void SetNegation(bool flag);
        void SetInverse(bool flag);
        
        size_t Hash() const;
        
#pragma mark private:
    private:
        //! Initialises a property attr and val from strings.
        void Init(const std::string& inAttribute, const std::string& inValue = "");
        
    private:
        Vindex_t mAttribute; //!< The attribute string mapped to an index.
        Vindex_t mValue;     //!< The value string mapped to an index.
        bool fNegation;      //!< The negation flag.
        bool fInverse;       //!< The inverse flag.
        
    };
    
    struct PropertyHash 
    {
        size_t operator()(const Property& p) const 
        {
            return p.Hash();
        }
        
        bool operator()(const Property& lhs, const Property& rhs) const 
        {
            return lhs < rhs;
        }
    };
    
} // namespace gre
} // namespace roman
} // namespace kutlak

#endif
